/*
 * Copyright (c) 2007 jNetX.
 * http://www.jnetx.com
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * jNetX. You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license
 * agreement you entered into with jNetX.
 *
 * $Id$
 */
package com.jnetx.javax.sip.util;

import java.text.ParseException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author <a href="mailto:dparhonin@jnetx.ru">Dmitry Parhonin</a>
 * @version $Revision$
 */
public final class Parametrized<T> implements Cloneable {
    private final T object;
    private final Map<String, Quoted> parameters = new HashMap<String, Quoted>();
    private final QuotationType defaultQuotationType;

    public Parametrized(T object) {
        this(object, QuotationType.NONE);
    }

    public Parametrized(T object, QuotationType qType) {
        this.object = object;
        this.defaultQuotationType = qType;
    }

    public T getObject() {
        return object;
    }

    public Map<String, Quoted> getParameters() {
        return parameters;
    }

    public void putParameters(Map<String, Quoted> source) {
        parameters.putAll(source);
    }

    public final String getParameter(String name) {
        final Quoted quoted = parameters.get(name);
        if (quoted != null)
            return quoted.getValue();
        else
            return null;
    }

    public final void setParameter(String name, String value) throws ParseException {
        parameters.put(name, new Quoted(value, defaultQuotationType));
    }

    public final void setParameter(String name, String value, QuotationType qType) throws ParseException {
        parameters.put(name, new Quoted(value, qType));
    }

    public final void setRawParameter(String name, String value) throws ParseException {
        parameters.put(name, new Quoted(value));
    }

    public final Iterator getParameterNames() {
        return parameters.keySet().iterator();
    }

    public final void removeParameter(String name) {
        parameters.remove(name);
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        final Parametrized<T> clone = new Parametrized<T>(this.object);
        clone.parameters.putAll(this.parameters);
        return clone;
    }

    public final String getParametersAsString() {
        return getParametersAsString(';');
    }

    public final String getParametersAsString(char delimiter) {
        final StringBuilder sb = new StringBuilder();
        if (parameters.size() != 0) {
            boolean isBegin = true;
            for (Map.Entry<String, Quoted> entry : parameters.entrySet()) {
                final String name = entry.getKey();
                final Quoted value = entry.getValue();
                if (!isBegin)
                    sb.append(delimiter);
                isBegin = false;
                sb.append(name).append('=').append(value);
            }
        }
        return sb.toString();
    }

    public String toString() {
        return object.toString() + ';' + getParametersAsString();
    }

    private static final class Quoted {
        private String value;
        private QuotationType type;

        public Quoted(String value, QuotationType type) {
            this.value = value;
            this.type = type;
        }

        public Quoted(String value) {
            value = value.trim();
            QuotationType qType = QuotationType.NONE;
            final int len = value.length();
            final char left = value.charAt(0);
            final char right = value.charAt(len - 1);
            if (len != 1) {
                if (left == right) {
                    if (left == '\'') {
                        qType = QuotationType.SINGLE;
                        value = value.substring(1, len - 1);
                    } else if (left == '\"') {
                        qType = QuotationType.DOUBLE;
                        value = value.substring(1, len - 1);
                    }
                } else {
                    if (left == '<' && right == '>') {
                        qType = QuotationType.ANGLE;
                        value = value.substring(1, len - 1);
                    }
                }
            }
            this.type = qType;
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public String toString() {
            return type.quotate(value);
        }
    }

    public enum QuotationType {
        UNKNOWN(' ', ' '), NONE(' ', ' '), SINGLE('\'', '\''), DOUBLE('"', '"'), ANGLE('<', '>');

        private final char left, right;

        QuotationType(char left, char right) {
            this.left = left;
            this.right = right;
        }

        public char getLeft() {
            return left;
        }

        public char getRight() {
            return right;
        }

        public String quotate(String str) {
            if (this == NONE || this == UNKNOWN)
                return str;
            else
                return left + str + right;
        }
    }
}
/*
 * $Log$
 */